package j_util;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.net.InetAddress;
import java.util.Enumeration;
import java.util.ResourceBundle;
/*

    This file is part of Logica-Logike.

    Logica-Logike is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation version 3 of the License.

    Logica-Logike is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Logica-Logike.  If not, see <http://www.gnu.org/licenses/>.

 */
/**
 * @author Jose Martin Rozanec;
 */
public class Utiles {
    static Dimension screenDimension = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
    static int MAXLINE = 80;
    static char ASTERIX = '*';
    static char BLANK = ' ';

    /**
     * Este metodo realiza una linea de n caracteres Considera maximo a imprimir, 80 caracteres
     *
     * @param n - int;
     * @param c - char;
     * @void;
     */
    public static void charLine(int n, char c) {
        for (int i = 0; n <= MAXLINE && i < n; i++) {
            System.out.print(c);
        }
    }

    /**
     * Este metodo realiza una linea de 80 caracteres (se considera 80 espacios igual a un renglon)
     *
     * @param c - char;
     * @void;
     */
    public static void charLine(char c) {
        for (int j = 0; j < MAXLINE; j++) {
            System.out.print(c);
        }
    }

    /**
     * Metodo que realiza una linea completa de asteriscos
     *
     * @void;
     */
    public static void charLine() {
        for (int j = 0; j < MAXLINE; j++) {
            System.out.print(ASTERIX);
        }
    }

    /**
     * Este metodo se utiliza para imprimir una linea centrada, formada por n caracteres;
     *
     * @param longitud - int;
     * @param caracter - char;
     * @void;
     */
    public static void centerLine(int longitud, char caracter) {
        int espacioRestante = MAXLINE - longitud;
        int espacioLateral = espacioRestante / 2;
        /*Este for imprime espacios*/
        for (int i = 0; i < espacioLateral; i++) {
            System.out.print("" + BLANK);
        }
        /*Este for imprime linea de caracteres*/
        for (int i = 0; i < longitud; i++) {
            System.out.print("" + caracter);
        }
        /*Este for es identico al primero*/
        for (int i = 0; i < espacioLateral; i++) {
            System.out.print("" + BLANK);
        }
    }

    /**
     * Metodo que centra un String dado en una linea de n caracteres, e imprime todo centrado en MAXLINE;
     *
     * @param n;
     * @param c;
     * @param s;
     */
    public static void centerLine(int n, char c, String s) {
        int stringLongitud = s.length();
        int charRestantes = n - stringLongitud;
        int espacioRestante;
        int espacioLateral;
        if (charRestantes >= 0) {
            espacioRestante = MAXLINE - n;
            int charLateral = charRestantes / 2;
            espacioLateral = espacioRestante / 2;
            /*Este for imprime espacios*/
            for (int i = 0; i < espacioLateral; i++) {
                System.out.print("" + BLANK);
            }
            /*Este for imprime los chars laterales*/
            for (int i = 0; i < charLateral; i++) {
                System.out.print("" + c);
            }
            System.out.print(s);
            /*Este for imprime los chars laterales*/
            for (int i = 0; i < charLateral; i++) {
                System.out.print("" + c);
            }
            /*Este for imprime espacios*/
            for (int i = 0; i < espacioLateral; i++) {
                System.out.print("" + BLANK);
            }
        }
    }

    /**
     * Este metodo permite imprimir un String centrado en MAXLINE
     *
     * @param s;
     * @void;
     */
    public static void centerString(String s) {
        int n = s.length();
        int espacioRestante = MAXLINE - n;
        int espacioLateral = espacioRestante / 2;
        for (int r = 0; r <= espacioLateral; r++) {
            System.out.print("" + BLANK);
        }
        System.out.print(s);
        for (int r = 0; r <= espacioLateral - 1; r++) {
            System.out.print("" + BLANK);
        }
        System.out.println("" + BLANK);
    }

    /**
     * Este metodo permite imprimir un menu, a partir de un arreglo de String menu, en el cual el primer String (String[0] menu) sera el titulo del menu;
     *
     * @param menuOpciones - String [] ;
     * @return int opcion;
     */
    public static int menu(String[] menuOpciones) {
        int longitudArreglo = menuOpciones.length;
        /*Imprimo titulo centrado en MAXLINE*/
        centerString(menuOpciones[0]);
        printline();
        /*Imprimo un menu para seleccionar con que objeto se va a operar*/
        for (int i = 1; i < longitudArreglo; i++) {
            System.out.println(menuOpciones[i]);
        }
        int opcion = KeyboardInput.integerValue("Elija una opcion valida del menu");
        int verifica = menuAuxiliar(opcion, menuOpciones);
        return verifica;
    }

    /**
     * Metodo auxiliar para metodo menu, cuyo fin es proporcionar "seguridad" al menu, obligando al usuario a elegir entre las opciones dadas;
     *
     * @param opcion;
     * @param menuOpciones - String [];
     * @return int verifica;
     */
    public static int menuAuxiliar(int opcion, String[] menuOpciones) {
        int verifica = 0;
        if (opcion == 0 || opcion > menuOpciones.length) {
            /*Imprimo titulo de menu*/
            centerString(menuOpciones[0]);
            printline();
            /*Este for reimprime el menu*/
            for (int i = 1; i < menuOpciones.length; i++) {
                System.out.println(menuOpciones[i]);
            }
            opcion = KeyboardInput.integerValue("Elija una opcion valida del menu");
            verifica = menuAuxiliar(opcion, menuOpciones);
        } else {
            return verifica;
        }
        return verifica;
    }

    /**
     * Este metodo permite imprimir un menu, a partir de un arreglo de String menu, en el cual el primer String (String[0] menu) sera el titulo del menu, y sera impreso en un recuadro de 20 espacios;
     *
     * @param menuOpciones - String [];
     * @return int opcion;
     */
    public static int menuDos(String[] menuOpciones) {
        int longitudArreglo = menuOpciones.length;
        /*Imprimo titulo centrado en MAXLINE*/
        squareMsg(20, menuOpciones[0]);
        printline();
        /*Imprimo un menu para seleccionar con que objeto se va a operar*/
        for (int i = 1; i < longitudArreglo; i++) {
            System.out.println(menuOpciones[i]);
        }
        int opcion = KeyboardInput.integerValue("Elija una opcion valida del menu");
        int verifica = menuAuxiliarDos(opcion, menuOpciones);
        return verifica;
    }

    /**
     * Metodo auxiliar para metodo menuDos, cuyo fin es proporcionar "seguridad" al menu, obligando al usuario a elegir entre las opciones dadas;
     *
     * @param opcion;
     * @param menuOpciones - String [];
     * @return int verifica;
     */
    public static int menuAuxiliarDos(int opcion, String[] menuOpciones) {
        int verifica = 0;
        if (opcion == 0 || opcion > menuOpciones.length) {
            /*Imprimo titulo de menu*/
            squareMsg(20, menuOpciones[0]);
            printline();
            /*Este for reimprime el menu*/
            for (int i = 1; i < menuOpciones.length; i++) {
                System.out.println(menuOpciones[i]);
            }
            opcion = KeyboardInput.integerValue("Elija una opcion valida del menu");
            verifica = menuAuxiliarDos(opcion, menuOpciones);
        } else {
            return verifica;
        }
        return verifica;
    }

    /**
     * Este metodo crea un recuadro de un ancho dado, e inserta en el, el contenido del String s;
     *
     * @param ancho;
     * @param s;
     * @void;
     */
    public static void squareMsg(int ancho, String s) {
        int espSinAsteriscos = ancho - 2;
        int longitudString = s.length();
        int i = 0;
        /*for que imprime asteriscos de la linea superior del recuadro*/
        for (; i <= ancho; i++) {
            System.out.print(ASTERIX);
            i++;
        }
        /*Condiciones para operar con el String y centrarlo en el recuadro*/
        if (longitudString <= ancho - 2) {
            squareMsgAux3(s, ancho);
        }
        if (longitudString > ancho - 2) {
            String[] strDividido = s.split(" ");
            int longitudArreglo = strDividido.length;
            int a = 0;
            for (; a < longitudArreglo; a++) {
                String division = squareMsgAux1(strDividido, ancho);/*Devuelve particion del string s*/
                squareMsgAux3(division, ancho);/*centra la particion de string s*/
                int longitudStrDivision = division.length();
                a = squareMsgAux2(strDividido, a, longitudStrDivision);/*reemplaza en a, el valor de posicion hasta el cual se corto el string s*/
            }
        }
    }

    /**
     * Este metodo se utiliza para verificar si es posible insertar dos o mas particiones de String en una fila;
     *
     * @param strDividido - String [];
     * @param ancho;
     * @return StringBuffer;
     */
    public static String squareMsgAux1(String[] strDividido, int ancho) {
        int espSinAsteriscos = ancho - 2;
        int d = 0;
        StringBuffer buff = new StringBuffer();
        int longStr = strDividido[d].length();
        int espacRest = espSinAsteriscos - longStr;
        for (; longStr <= MAXLINE - 2 && longStr <= espacRest; d++) {
            buff = buff.append(strDividido[d]);
            espSinAsteriscos = espSinAsteriscos - longStr;
        }
        String devolver = buff.toString();
        return devolver;
    }

    /**
     * Este metodo se utiliza para buscar la posicion en la que se corta el string;
     *
     * @param strDividido            - String [];
     * @param posicionDeUltimoCorte;
     * @param longitudStrDivision;
     * @return int;
     */
    public static int squareMsgAux2(String[] strDividido, int posicionDeUltimoCorte, int longitudStrDivision) {
        int d = posicionDeUltimoCorte;
        int espSinAsteriscos = longitudStrDivision - 2;
        StringBuffer buff = new StringBuffer();
        int longStr = strDividido[d].length();
        int espacRest = espSinAsteriscos - longStr;
        for (; longStr <= MAXLINE - 2 && longStr <= espacRest; d++) {
            buff.append(strDividido[d]);
            espSinAsteriscos = espSinAsteriscos - longStr;
        }
        return d;
    }

    /**
     * Este metodo se encarga de centrar el String dividido, colocando los asteriscos correspondientes a derecha e izquierda;
     *
     * @param s      - String;
     * @param ancho;
     * @void;
     */
    public static void squareMsgAux3(String s, int ancho) {
        int str = s.length();
        int espRest = ancho - str - 2;/*Espacio restante en el recuadro, descontando el espacio de los asteriscos*/
        int espLat = espRest / 2;/*espacio lateral en el recuadro*/
        System.out.print(ASTERIX);
        /*recursivo para centrar String que se acomoda al cuadro*/
        for (int i = 0; i <= espLat; i++) {
            System.out.print(BLANK);
        }
        System.out.print(s);
        /*Ciclo para colocar el asterisco en el lado derecho del cuadro*/
        for (int j = 0; j <= espLat; j++) {
            System.out.print(BLANK);
        }
        System.out.print("" + ASTERIX);
    }

    /**
     * Este metodo sirve para imprimir una linea vacia;
     *
     * @void;
     */
    public static void printline() {
        System.out.println("");
    }

    /**
     * This class is prints a menu and asks to chose an option;
     *
     * @param title - Menu title;
     * @param menu  - menu options array;
     * @return int selected option;
     */
    public static int menu(String title, String[] menu) {
        int opcion = -1;
        System.out.println("\t\t" + title);
        do {
            for (int i = 0; i < menu.length; i++) {
                System.out.println("" + menu[i]);
            }
            opcion = KeyboardInput.integerValue("Insert an option.");
        } while ((opcion < 1) && (opcion > menu.length));
        return opcion;
    }

    /**
     * This method has the purpose of formatting a specified string, in order to get an appropiate String for a limited
     * JTextArea, JLabel or other component. Also may be used wherever exists the need of showing a String in a limited
     * width space;
     *
     * @param original - original String
     * @param witdth   - characters in width;
     * @return formatted String;
     */
    public static String formatString(String original, int witdth) {
        StringBuffer stringBuffer = new StringBuffer();
        StringBuffer temp;
        int lastIndex = 0;
        int length = original.length() / witdth;
        String[] arrayByCarriageReturn = original.split("\n");
        for (int k = 0; k < arrayByCarriageReturn.length; k++) {
            stringBuffer.append("\n");
            String[] array = arrayByCarriageReturn[k].split(" ");
            int i = 0;
            int j = 0;
            boolean stop = false;
            while (!stop) {
                j = 0;
                temp = new StringBuffer();

//                array[0]=array[0].replace(" ","");
                while (j != 2) {
                    if (i < array.length) {
                        if ((temp.toString().length() + array[i].length()) > witdth) {
                            j = 2;
                        } else {
                            temp.append(array[i] + " ");
                            i++;
                        }
                    } else {
                        j = 2;
                        stop = true;
                    }
                }
                stringBuffer.append(temp.toString() + "\n");
            }
        }
        return stringBuffer.toString();
    }


    /**
     * * This method is used to center the JFrame;
     *
     * @param frame - JFrame;
     */
    public static void centerFrame(JFrame frame) {
        int w = frame.getSize().width;
        int h = frame.getSize().height;
        int x = (screenDimension.width - w) / 2;
        int y = (screenDimension.height - h) / 3;
        frame.setLocation(x, y);
    }

    public static int[] getCenteredFrameCoordinates(JFrame frame) {
        int coordinates[] = new int[2];
        coordinates[0] = (screenDimension.width - frame.getSize().width) / 2;
        coordinates[1] = (screenDimension.height - frame.getSize().height) / 3;
        return coordinates;
    }

    /**
     * * This method is used to center the JDialog;
     *
     * @param dialog - JDialog;
     */
    public static void centerDialog(JDialog dialog) {
        int w = dialog.getSize().width;
        int h = dialog.getSize().height;
        int x = (screenDimension.width - w) / 2;
        int y = (screenDimension.height - h) / 4;
        dialog.setLocation(x, y);
    }

    /**
     * This method is used to create an ImageIcon;
     *
     * @param path - String
     * @return ImageIcon
     */
    public static ImageIcon createImageIcon(String path) {
        java.net.URL imgURL = Toolkit.class.getResource(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL);
        } else {
            return null;
        }
    }

    /**
     * This method allows to create directories specified in name String. The method will create the directories
     * taking as root, the directory were the Jaa aplication is running;
     *
     * @param name - String;
     * @return directory path - String;
     */
    public static String createDirectory(String name) {
        String directories = System.getProperty("user.dir") + "/" + name;
        boolean success = (new File(directories)).mkdirs();
        System.out.println("success: " + success);
        return directories;
    }

    /**
     * Allows to get relative path from a base path and the desired one;
     *
     * @param base
     * @param path
     * @return
     */
    public static String getRelativePath(String base, String path) {
        String path1 = new File(base).toURI().relativize(new File(path).toURI()).getPath();
        String path2 = new File(path).toURI().relativize(new File(base).toURI()).getPath();
        if (countOccurrences(path1, "/") < countOccurrences(path2, "/")) {
            return path1;
        } else {
            return path2;
        }
    }

    /**
     * Builds relative path taking $home directory as reference;
     *
     * @param path
     * @return
     */
    public static String getPathFromHome(String path) {
        int ocurrences = Utiles.countOccurrences(getRelativePath(System.getProperty("user.home"), path), "/");
        StringBuffer buffer = new StringBuffer();
        for (int j = 0; j < ocurrences; j++) {
            buffer.append("../");
        }
        String difference = path.replace(System.getProperty("user.home"), "");
        return buffer.toString() + difference;
    }

    /**
     * This method allows to get directories absolute path, while a directory was created considering Java
     * applications directory as root;
     *
     * @param name
     * @return
     */
    public static String getDirectory(String name) {
        return System.getProperty("user.dir") + "/" + name;
    }

    /**
     * Returns filepath with the specified extension, avoiding duplicate
     * extension if the path string already includes the extension;
     *
     * @param path;
     * @param extension;
     * @return String;
     */
    public static String getFilePathWithExtension(String path, String extension) {
        if (!extension.startsWith(".")) {
            extension = "." + extension;
        }
        if (!path.endsWith(extension)) {
            path = path.concat(extension);
        }
        return path;
    }

    /**
     * Alerts about an existing file with the same name before saving. It does not overwrite a file in that case;
     *
     * @param path;
     * @param extension;
     * @param text;
     */
    public static void saveTextFileAlertingOverwrite(String path, String extension, String text) {
        if (!extension.startsWith(".")) {
            extension = "." + extension;
        }
        if (!path.endsWith(extension)) {
            path = path.concat(extension);
        }
        File file = new File(path);
        if (file.exists()) {
            JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "El archivo seleccionado ya existe!", "", JOptionPane.WARNING_MESSAGE);
        } else {
            try {
                RandomAccessFile randomAccessFile = new RandomAccessFile(path, "rw");
                randomAccessFile.writeUTF(text);
            } catch (FileNotFoundException e1) {
                e1.printStackTrace();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }

    /*
     * Get the extension of a file.
     */
    public static String getExtension(File f) {
        String ext = null;
        String s = f.getName();
        int i = s.lastIndexOf('.');

        if (i > 0 && i < s.length() - 1) {
            ext = s.substring(i + 1).toLowerCase();
        }
        return ext;
    }

    /**
     * Returns a String with the number of ' ' chars requested;
     *
     * @param spaces - number of ' ' charanters;
     * @return s String concatenation of ' ' chars
     */
    public static String getSpacesString(int spaces) {
        StringBuffer buffer = new StringBuffer();
        for (int j = 0; j < spaces; j++) {
            buffer.append(Utiles.BLANK);
        }
        return buffer.toString();
    }

    /**
     * Returns an HTML code formatting the Strings passed;
     *
     * @param bold    - String to be displayed in bold;
     * @param notBold - String to be displayed not bold;
     * @return formatted String;
     */
    public static String getFormattedString(String bold, String notBold) {
        StringBuffer buffer = new StringBuffer();
        buffer.append("<html><b>" + bold + "</b>");
        buffer.append(notBold);
        buffer.append("</html>");
        return buffer.toString();
    }

    /**
     * Returns an HTML code formatting the Strings passed;
     *
     * @param bold         - String to be displayed in bold;
     * @param notBold      - String to be displayed not bold;
     * @param stringLength - length of the total String, uses <pre> tag to consider spaces
     * @return
     */
    public static String getFormattedString(String bold, String notBold, int stringLength) {
        StringBuffer buffer = new StringBuffer();
        buffer.append("<html><pre><b>" + bold + "</b>");
        buffer.append(notBold);
        buffer.append(getSpacesString(stringLength - bold.length() - notBold.length()));
        buffer.append("</pre></html>");
        return buffer.toString();
    }

    /**
     * Returns a random int according to the timestamp;
     *
     * @param max
     * @return
     */
    public static int getRandomInt(int max) {
        int random;
        random = (int) System.currentTimeMillis() % (max);
        if (random < 0) {
            random = random * (-1);
        }
        return random;
    }

    /**
     * Lists all files in a directory;
     *
     * @param directoryFilePath - directoru file path;
     * @return a File array;
     */
    public static File[] listFilesInDirectory(String directoryFilePath) {
        java.io.File file = new java.io.File(directoryFilePath);
        return file.listFiles();
    }

    /**
     * Gets all files listed in the specified directory and all the subdirectories. Works as a file spider;
     *
     * @param directoryFilePath
     * @param fileList
     */
    public static void getAllFilesListedInSubdirectories(String directoryFilePath, java.util.List<File> fileList) {
        File[] files = listFilesInDirectory(directoryFilePath);
        for (int j = 0; j < files.length; j++) {
            if (files[j].isDirectory()) {
                getAllFilesListedInSubdirectories(files[j].getAbsolutePath(), fileList);
            } else {
                fileList.add(files[j]);
            }
        }
    }

    /**
     * Prints filechooser BundleResources;
     */
    public static void printFilechooserBundleResources() {
        ResourceBundle bundle = ResourceBundle.getBundle("com.sun.swing.internal.plaf.basic.resources.basic");
        Enumeration<String> keyEn;
        keyEn = bundle.getKeys();
        System.out.println("Getting all keys, have more elements: " + keyEn.hasMoreElements());
        while (keyEn.hasMoreElements()) {
            String key = keyEn.nextElement();
            if (key.indexOf("FileChooser") != -1) {
                System.out.println(key + ":" + bundle.getString(key));
            }
        }
    }

    /**
     * Returns local IP in String representation. If an error occurs, returns null;
     *
     * @return IP - String;
     */
    public static String getIP() {
        try {
            InetAddress thisIp = InetAddress.getLocalHost();
            return thisIp.getHostAddress();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * This method returns a JPanel whith the given JLabel and the JTextField;
     *
     * @param label
     * @param field
     * @return a JPanel;
     */
    public static JPanel getLabelFieldPanel(JLabel label, JTextField field) {
        JPanel panel = new JPanel();
        panel.add(label);
        panel.add(field);
        panel.setBackground(Color.WHITE);
        return panel;
    }

    public static JPanel getLabelFieldLabelPanel(JLabel label, JTextField field, JLabel secondLabel) {
        JPanel panel = new JPanel();
        panel.add(label);
        panel.add(field);
        panel.add(secondLabel);
        panel.setBackground(Color.WHITE);
        return panel;
    }

    /**
     * Checks if the String passed has a valid IP format;
     *
     * @param ip
     * @return
     */
    public static boolean checkIPFormat(String ip) {
        boolean correct = true;
        ip = ip.replace(".", ",");
        String[] array = ip.split(",");
        int subIP;
        if (array.length == 4) {
            for (int j = 0; j < array.length; j++) {
                subIP = Integer.parseInt(array[j]);
                if (subIP < 0 || subIP > 255) {
                    correct = false;
                }
            }
//            array = array[3].split(":");
//            correct=correct&&(array[0].length()==3);
        } else {
            correct = false;
        }
        return correct;
    }

    /**
     * This method deserializes an object saved in a specified filepath;
     *
     * @param filepath;
     * @return the deserialized object or null if an error ocurred;
     */
    public static <T> T deserialize(String filepath) {
        File file = new File(filepath);
        ObjectInputStream in = null;
        try {
            in = new ObjectInputStream(new FileInputStream(file));
            T deserializedObject = (T) in.readObject();
            in.close();
            return deserializedObject;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * This method serializes an object in a specified filepath;
     *
     * @param object;
     * @param outputFilepath;
     */
    public static <T> void serialize(T object, String outputFilepath) {
        try {
            ObjectOutput out = new ObjectOutputStream(new FileOutputStream(outputFilepath));
            out.writeObject(object);
            out.close();
        } catch (IOException e) {
        }
    }

    /**
     * Devuelve la representacion en numeros romanos del entero que se le pase;
     *
     * @param number;
     * @return String - representacion en numeros romanos;
     */
    public static String getRomanNumberRepresentation(int number) {
        String roman = "";
        int n = number;
        while (n >= 1000) {
            roman += "M";
            n -= 1000;
        }
        while (n >= 900) {
            roman += "CM";
            n -= 900;
        }
        while (n >= 500) {
            roman += "D";
            n -= 500;
        }
        while (n >= 400) {
            roman += "CD";
            n -= 400;
        }
        while (n >= 100) {
            roman += "C";
            n -= 100;
        }
        while (n >= 90) {
            roman += "XC";
            n -= 90;
        }
        while (n >= 50) {
            roman += "L";
            n -= 50;
        }
        while (n >= 40) {
            roman += "XL";
            n -= 40;
        }
        while (n >= 10) {
            roman += "X";
            n -= 10;
        }
        while (n >= 9) {
            roman += "IX";
            n -= 9;
        }
        while (n >= 5) {
            roman += "V";
            n -= 5;
        }
        while (n >= 4) {
            roman += "IV";
            n -= 4;
        }
        while (n >= 1) {
            roman += "I";
            n -= 1;
        }
        return roman;
    }

    public static void printMatrix(Object[][] matrix) {
        System.out.println("" + matrix.length);
        System.out.println("" + matrix[0].length);
        if (matrix.length < matrix[0].length) {
            for (int j = 0; j < matrix.length; j++) {
                for (int i = 0; i < matrix[0].length; i++) {
                    System.out.print("" + matrix[j][i]);
                }
                System.out.println("");
            }
        } else {
            for (int j = 0; j < matrix[0].length; j++) {
                for (int i = 0; i < matrix.length; i++) {
                    System.out.print("" + matrix[i][j]);
                }
                System.out.println("");
            }
        }
    }

    public static boolean isNumber(String string) {
        string = string.replace("0", "").replace("1", "").replace("2", "").replace("3", "").replace("4", "");
        System.out.println("String: " + string);
        string = string.replace("5", "").replace("6", "").replace("7", "").replace("8", "").replace("9", "");
        string = string.replace(".", "");
        return string.equals("");
    }

    public static String formatXML(String xml) {
        int indents = 0;
        boolean restarIndentacion = false;
        char[] xmlChars = xml.toCharArray();
        StringBuffer formattedXML = new StringBuffer();
        StringBuffer phrase = new StringBuffer();
        for (int j = 0; j < xmlChars.length; j++) {
            if (xmlChars[j] == '<') {
                System.out.println("indent: " + indents + " ; " + phrase);
                if (phrase.toString().equals("")) {
                    formattedXML.append(getIndents(indents) + phrase);
                } else {
                    formattedXML.append(getIndents(indents) + phrase + "\n");
                }
                phrase = new StringBuffer();
                phrase.append(xmlChars[j]);
//                indents++;
            } else {
                if (xmlChars[j] == '/') {
                    phrase.append(xmlChars[j]);
                    restarIndentacion = true;
                } else {
                    if (xmlChars[j] == '>') {
                        formattedXML.append(getIndents(indents) + phrase + "" + xmlChars[j] + "\n");
                        phrase = new StringBuffer();
                        if (!restarIndentacion) {
                            indents++;
                        } else {
                            restarIndentacion = false;
                            indents--;
                        }
                    } else {
                        phrase.append(xmlChars[j]);
                    }
                }
            }
        }
        return formattedXML.toString();
    }

    private static String getIndents(int indents) {
        StringBuffer buffer = new StringBuffer();
        for (int j = 0; j < indents; j++) {
            buffer.append("    ");
        }
        return buffer.toString();
    }

    public static String removeSpacesFromString(String string) {
        return string.replace(" ", "");
    }

    /**
     * Count number of occurrences of arg2 in arg1.
     *
     * @param arg1
     * @param arg2
     * @return int
     */
    public static int countOccurrences(String arg1, String arg2) {
        int count = 0;
        int index = 0;
        while ((index = arg1.indexOf(arg2, index)) != -1) {
            ++index;
            ++count;
        }
        return count;
    }

    /**
     * Creates the requested file;
     *
     * @param filename  - file path and name;
     * @param data      - formatted String: columns are separated by commas, rows are separated by carriage return;
     * @param sheetName - MSExcel sheet name;
     */
    public static void exportToXLS(String filename, String data, String sheetName) {
        filename = getFilePathWithExtension(filename, ".xls");
        Workbook wb = new HSSFWorkbook();
        excelExportingAuxiliary(wb, filename, data, sheetName);
    }

    /**
     * Creates the requested file;
     *
     * @param filename  - file path and name;
     * @param data      - formatted String: columns are separated by commas, rows are separated by carriage return;
     * @param sheetName - MSExcel sheet name;
     */
    public static void exportToXLSX(String filename, String data, String sheetName) {
        filename = getFilePathWithExtension(filename, ".xlsx");
        Workbook wb = new XSSFWorkbook();
        excelExportingAuxiliary(wb, filename, data, sheetName);
    }

    /**
     * Performs necessary operations to fill the sheet with the requested data;
     *
     * @param wb
     * @param filename
     * @param data
     * @param sheetName
     */
    private static void excelExportingAuxiliary(Workbook wb, String filename, String data, String sheetName) {
        org.apache.poi.ss.usermodel.Sheet sheet = wb.createSheet(sheetName);
        CreationHelper createHelper = wb.getCreationHelper();
        String[] rows = data.split("\n");
        CellStyle style = wb.createCellStyle();
        style.setFillBackgroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        style.setFillPattern(CellStyle.SOLID_FOREGROUND);
        String[] columns;
        Row row;
        Cell cell;
        for (int j = 0; j < rows.length; j++) {
            columns = rows[j].split(",");
            row = sheet.createRow((short) j);
            for (int s = 0; s < columns.length; s++) {
                cell = row.createCell(s);
                cell.setCellValue(createHelper.createRichTextString(columns[s]));
                if (j == 0) {
                    cell.setCellStyle(style);
                }
            }
        }
        FileOutputStream fileOut = null;
        try {
            fileOut = new FileOutputStream(filename);
            wb.write(fileOut);
            fileOut.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}